
#pragma once


#include "IClientRoot.h"
#include "SkinSystem.h"
#include "RegisterGUI.h"

    class RenderEngineSystem;
	class TiXmlElement;
namespace Apo
{
	class OGUIWidget;
	class OGUICategoryBar;
	class UpdateEvent;
	class CommandEvent;
	class EditNode;
	class DynLib;
	class CBaseSerializer;
	class UndoManager;

	//typedef HashMap<int,OGUIWidget*> WidgetMap;
	typedef AlignedObjectArray<OGUIWidget*> WidgetVector;
	typedef AlignedObjectArray<OGUICategoryBar*> CategoryBarVector;
	/// A Hashed by Name Storage Definition for All Serializers
	typedef   HashMap<btHashString,CBaseSerializer*> SerializerMap;

	class SocketClientLibExport ApoRootListener
	{
	public:
		ApoRootListener() {};
		virtual ~ApoRootListener() {};

		virtual void OnTerminateScene() = 0;
		virtual void OnAfterLoadScene() = 0;
		virtual void OnUpdate(float time) = 0;
	};

	/// This is the Root Class in Charge of All Editors

	class  SocketClientLibExport ClientRoot  : public IClientRoot
	{
		friend class CBaseEditor;
	public:
		/// Constructor, Initialise with a Platform Dependant System Class
		ClientRoot();
		/// Destructor
		~ClientRoot();
		static	ClientRoot & getInstance();
		//LOAD PLUGIN 
		void            init(const char * pluginFile = "ClientPlugin.cfg",const char * logFile = "log.log");
		void			initPlugincfg(const char *plugin);
		const char *    getExePath();
		//void			deleteBoneEntity();
		/// Does the Cleanup between loading scene files
		void            ClearEditors();
		/// Loads an Ogitor Plugin
		void            LoadPlugin(String pluginName);
		/// UnLoads all Ogitor Plugins
		void            UnLoadPlugins();
		/// Registers a new Root Listener
		void            RegisterRootListener(ApoRootListener *listener);
		/// UnRegisters a new Root Listener
		void            UnRegisterRootListener(ApoRootListener *listener);
		/// Notifies all RootListeners of Terminate Scene
		inline void     NotifyOnTerminateScene();
		/// Notifies all RootListeners of Scene Loaded
		inline void     NotifyOnAfterLoadScene();
		/// Notifies all RootListeners of Update
		inline void     NotifyOnUpdate(float time);

		HashMap<btHashString,RenderEngineSystem*> mRenderMap;
		/// Registers a new Render to Hash Table
		void            RegisterRender(RenderEngineSystem *serializer);
		/// Returns a StringVector filled with registered Render Type Names
		void            GetRenderList(StringVector &list);

		//
		RenderEngineSystem *       GetRenderSystemPoint();
		void				       SetCurrentRenderSystemPoint(const char * name);

		/// Registers a new Editor Object Type to Hash Table
		void            RegisterObjectType(String typestring,OGITORREGISTRATIONSTRUCT &data);
		/// Registers a new Category Bar
		void            RegisterCategoryBar(OGUICategoryBar *category);
		/// Registers a new Serializer to Hash Table
		void            RegisterSerializer(CBaseSerializer *serializer);
		/// Returns a StringVector filled with registered Serializer Type Names
		void            GetSerializerList(StringVector &list);


		/// Returns a StringVector filled with registered Serializer Type Names capable of Export
		void            GetExportSerializerList(StringVector &list);
		/// Returns a StringVector filled with registered Serializer Type Names capable of Import
		void            GetImportSerializerList(StringVector &list);
		/// Triggers a Serializer for Import
		bool            TriggerImportSerializer(String name);
		/// Triggers a Serializer for Export
		bool            TriggerExportSerializer(String name);

		/// Returns Registration Data of an Editor Object Type
		OGITORREGISTRATIONSTRUCT *GetTypeData(String typestring);
		/// Returns Type ID of a Type String or 0 if not found
		unsigned int    GetTypeID(String typestring);
		/// Returns ID sorted Editor Type List
		StringVector GetSortedTypeList();
		void            RegisterObjectName(String name,CBaseEditor *obj);
		/// Unregisters an Object (Called Upon Deletion of Object
		void            UnRegisterObjectName(String name,CBaseEditor *obj);
		/// This function is a bridge between ETL and Hydrax, called when ETL material changes
		void            OnTerrainMaterialChange(CBaseEditor *terrainobject);
		/// All Objects register themselves for updates if they need to update every frame
		void            RegisterForUpdates(CBaseEditor *object);
		/// Unregister from update queue
		void            UnRegisterForUpdates(CBaseEditor *object);


		void			RegisterForRenders(CBaseEditor *object);
		//-----------------------------------------------------------------------------------------
		void			UnRegisterForRenders(CBaseEditor *object);

		/// This function should be called every frame in Frame Started
		bool            Update(float timePassed);
		bool			frameRenderingQueued(float timePassed);
		/// All Objects register themselves for updates if they need to update when scene is loaded
		void            RegisterForPostSceneUpdates(CBaseEditor *object);
		/// find Child By Name, you can supply object type to speed up the process
		CBaseEditor    *FindObject(String name, unsigned int type = 0);
		/// Get all objects of a type
		const NameObjectPairList GetObjectsByType(unsigned int type);
		/// Get all objects of a type ID
		const NameObjectPairList GetObjectsByTypeName(String typestring);
		/// Get all objects of a type ID in a vector (Use this while saving scene since it also orders the items)
		void            GetObjectList(unsigned int type, ObjectVector& list);
		/// Gets the BaseEditor Object
		CBaseEditor    *GetRootEditor() {return m_RootEditor;};
		/// Empities the Project Optins
		void            ClearProjectOptions();
		/// Returns pointer to Project Options
		PROJECTOPTIONS *GetProjectOptions() {return &m_ProjectOptions;}
		/// Get a list of all registered Category Bars
		const CategoryBarVector GetCategoryBars() {return m_CategoryBars;};

		/// Loads a Scene from a given file
		int             LoadScene(String m_Filename);

		/// Saves / Saves As Scene
		bool            SaveScene(bool SaveAs = false);

		/// Terminates Scene
		bool            TerminateScene();

		/// Does necessary operations after a Scene Loaded
		bool            AfterLoadScene();

		/// Loads Project Options from a given TiXmlElement
		bool            LoadProjectOptions(TiXmlElement *optRoot);

		/// Loads Camera Positions from a given TiXmlElement
		bool            OptionsReadCameraPositions(TiXmlElement *parent);

		/// Loads Directory List from a given TiXmlElement
		bool            OptionsReadDirectories(TiXmlElement *parent, StringVector &pDir);

		/// Prepares Project Resource Groups
		void            PrepareProjectResources();

		/// Converts relative project resource paths according to new Project Directory
		void            AdjustUserResourceDirectories(String oldpath);

		/// Creates an Editor Object using registered factory
		CBaseEditor    *CreateEditorObject(CBaseEditor *parent, const String objecttypestring,NameValuePairList &params,bool addtotreelist = false, bool display = false);

		/// Clones an Editor Object using registered factory
		CBaseEditor    *CloneEditorObject(CBaseEditor *object,bool addtotreelist = false, bool display = false);

		/// Renames an Editor Object using registered factory
		CBaseEditor    *RenameEditorObject(CBaseEditor *object, const String &name, bool addtotreelist = false, bool display = false);

		/// Destroys an Editor Object using registered factory
		void            DestroyEditorObject(CBaseEditor *object, bool removefromtreelist = false, bool display = false);

		/// Returns if Object's Factory Can Instantiate an object Identified by its TypeName
		bool            CanInstantiateObject(String typestring);

		void            OnCustomGUI(int ID);

		UpdateEvent     OnUpdateCustomGUI(int ID);

		static inline void SetControlIDBase(int baseID) {m_NextGUIControlID = baseID;};

		static inline int  GetCurrentControlID() {return m_NextGUIControlID;};

		unsigned int       GetNextControlID(OGUIWidget *widget);

		void               TerminateGUIControl(OGUIWidget *widget);

		OGUIWidget        *GetGUIWidgetBySystemID(int ID);

		// UTILITY FUNCTIONS

		String    CreateUniqueID(String n1, String n2);
		void            WriteCameraPositions(String &outstream, bool addcurrent);
		void            WriteProjectOptions(String &outstream, bool newproject);

		void            LoadPropertySheets();
		void            UnloadPropertySheets();
		void            LoadCustomProperties();
		CUSTOMPROPERTY *GetCustomProperty(String name);
		unsigned int    GetCustomPropertyID(String name);
		String    GetCustomPropertyTypeName(unsigned int ID);
		void            RecurseAddCustomProperty(CUSTOMPROPERTY *to, CUSTOMPROPERTY *from);
		void            RecurseDeleteCustomProperties(CUSTOMPROPERTY *p);
		void            GetCustomPropertyList(unsigned int editortype, StringVector &result);
		bool            HasTreeView();
		bool            HasPropertiesView();
		bool            ClearPropertiesView(unsigned int TypeID);
		void            SelectTreeItem(String name);
		void            SetTreeItemText(String oldname, String newname);
		void *          InsertTreeItem(String parent,String name,int iconid, unsigned int colour);
		void *          InsertTreeItem(void *parent,String name,int iconid, unsigned int colour);
		void            DeleteTreeItem(String name);
		void            FillTreeView();

		// Light::LightTypes ConvertLightType(String val);

// 		void GetMeshInformationEx(const MeshPtr mesh, size_t &vertex_count,
// 			Vector3* &vertices, size_t &index_count,
// 			unsigned long* &indices,
// 			const Vector3 &position,
// 			const Quaternion &orient,
// 			const Vector3 &scale);

		//     bool          PickEntity(RaySceneQuery* mRaySceneQuery, Ray &ray, Entity **result, Vector3 &hitpoint);
		//     bool          PickWidget(RaySceneQuery* mRaySceneQuery, Ray &ray, int &Axis);
		// 	Plane   FindGizmoTranslationPlane(Ray &pickRay, int TranslationAxis);
		// 	Vector3 GetGizmoIntersect(Ray &pickRay, Plane &planetouse, int TranslationAxis, Vector3 &vLastPosition);
		//     bool          WorldIntersect(RaySceneQuery* mRaySceneQuery, Ray &ray, Vector3 &hitposition);
		//     void          VolumeSelect(Ray &topLeft, Ray &topRight, Ray &bottomLeft, Ray &bottomRight, NameObjectPairList &result);

		//void          FillResourceGroup(ResourceGroupManager *mngr,StringVector &list,String path,String group);

		/// Returns the Currently Selected Object
		inline CBaseEditor *            GetSelected() {return m_SelectedEditor;};
		/// Sets the Currently Selected Object
		inline void                     SetSelected(CBaseEditor *selected) {m_SelectedEditor = selected;m_OldWidgetMode = 256;m_OldWidgetAxis = 256;};
		/// Returns the names of materials in User Assets Folders
		inline const StringVector GetMaterialNames() {return m_MaterialNames;};
		/// Sets the material names list
		inline void                     SetMaterialNames(StringVector &names) {m_MaterialNames = names;};
		/// Sets current Render Window
		// 	inline void                     SetRenderWindow(RenderWindow *window) {m_RenderWindow = window;};
		// 	/// Returns Current Render Window
		// 	inline RenderWindow *     GetRenderWindow() {return m_RenderWindow;};
		// 	/// Returns Current Viewport
		// 	inline CViewportEditor *        GetViewport() {return m_ActiveViewport;};
		/// Sets Active Viewport
		// 	inline void                     SetActiveViewport(CViewportEditor *viewport) {m_ActiveViewport = viewport;};
		// 	/// Returns current SceneManager, if not found, returns the first Scene Manager in the list
		// 	inline SceneManager *     GetSceneManager()
		// 	{
		// 	 if(!m_SceneManager)
		// 	   m_SceneManager = GetFirstSceneManager();
		// 	 return m_SceneManager;
		// 	};

		/// Returns current SceneManagerEditor, if not found, returns the first Scene Manager in the list
		inline CBaseEditor * GetSceneManagerEditor()
		{
// 			if(!m_SceneManagerEditor)
// 				m_SceneManagerEditor = FindObject(GetFirstSceneManager()->getName(), ETYPE_SCENEMANAGER);
			return m_SceneManagerEditor;
		};

		// 	inline iCamera *              GetCameraEditor() { return  dynamic_cast<iCamera*>(&m_CameraManager);};
		// 	inline iSoundEditor *         GetSoundEditor()  { return   m_iSoundEditor;};
		// 	inline iAvatar *               GetAvatarEditor() {return m_iAvatar;};
		// 	inline CTerrainEditor *         GetTerrainEditor() {return m_TerrainEditor;};
		//     inline CBaseEditor *            GetTerrainEditorObject() {return m_TerrainEditorObject;};

		/// Returns the first Scene Manager in the list
			//SceneManager *            GetFirstSceneManager();

		/// Returns if Modifications made to the scene after it is loaded
		inline bool                      IsSceneModified() {return m_IsSceneModified;};
		/// Returns if there is an active loaded Scene
		inline bool                      IsSceneLoaded() {return m_IsSceneLoaded;};
		/// Sets if Modifications made to the scene after it is loaded
		inline void                      SetSceneModified(bool modified) {m_IsSceneModified = modified;};
		/// Sets the modification state of a Scene only if the value is true (Additive)
		inline void                      ChangeSceneModified(bool state) {m_IsSceneModified |= state;};

		void                             HideSelectionRect();
		//void                             ShowSelectionRect(Vector4 size);
		//Higlights Widget Axis
		void                             HiLiteWidget(int ID);
		/// Changes the look of Widget to one of Select/Move/Rotate/Scale
		void                             SetWidgetMode(int mode);

		inline bool                      GetLightVisiblity() {return m_GlobalLightVisiblity;};
		inline bool                      GetCameraVisiblity() {return m_GlobalCameraVisiblity;};
		void                             SetLightVisiblity(bool visibility); 
		void                             SetCameraVisiblity(bool visibility);

		// inline CMultiSelEditor *         GetMultiSelection() {return m_MultiSelection;}

		void                             RenderWindowResized();

		inline void                      ClearScreenBackground(bool bClear) {m_ClearScreenBackground = bClear;};
		inline bool                      IsClearScreenNeeded() {return m_ClearScreenBackground;};

		///EVENTS

		/** Keyboard events callback.
		@remarks This will handle Key Down Event.
		@param evt Data regarding the key event.
		*/
		void OnKeyDown (unsigned int key);

		/** Keyboard events callback.
		@remarks This will handle Key Up Event.
		@param evt Data regarding the key event.
		*/
		void OnKeyUp (unsigned int key);

		/** Mouse events callback.
		@remarks This will handle Mouse Move Event.
		@param evt Data regarding the mouse event.
		*/
		void OnMouseMove (Vector2 point, unsigned int buttons);

		/** Mouse events callback.
		@remarks This will handle Mouse Leave Event.
		@param evt Data regarding the mouse event.
		*/
		void OnMouseLeave (Vector2 point, unsigned int buttons);

		/** Mouse events callback.
		@remarks This will handle Left Mouse Down Event.
		@param evt Data regarding the mouse event.
		*/
		void OnMouseLeftDown (Vector2 point, unsigned int buttons);

		/** Mouse events callback.
		@remarks This will handle Left Mouse Up Event.
		@param evt Data regarding the mouse event.
		*/
		void OnMouseLeftUp (Vector2 point, unsigned int buttons);

		/** Mouse events callback.
		@remarks This will handle Right Mouse Down Event.
		@param evt Data regarding the mouse event.
		*/
		void OnMouseRightDown (Vector2 point, unsigned int buttons);

		/** Mouse events callback.
		@remarks This will handle Middle Mouse Down Event.
		@param evt Data regarding the mouse event.
		*/
		void OnMouseMiddleDown (Vector2 point, unsigned int buttons);

		/** Mouse events callback.
		@remarks This will handle Middle Mouse Up Event.
		@param evt Data regarding the mouse event.
		*/
		void OnMouseMiddleUp (Vector2 point, unsigned int buttons);

		/** Mouse events callback.
		@remarks This will handle Right Mouse Up Event.
		@param evt Data regarding the mouse event.
		*/
		void OnMouseRightUp (Vector2 point, unsigned int buttons);

		/** Mouse events callback.
		@remarks This will handle Mouse Wheel Event.
		@param evt Data regarding the mouse event.
		*/
		void OnMouseWheel (Vector2 point, float delta, unsigned int buttons);
		
	private:
		static  unsigned int m_NextGUIControlID;
		stringvector m_pluginlist;
		typedef HashMap<btHashString ,int> FileMap;
		FileMap m_FileMap;
		void checkDoubleFile(const StringVector & dirlist);
		void searchResources(String resource_path, StringVector *ResourceDirectories);
		void FindAllFile( String resource_path = "..\\Media\\avatar\\animation\\*.skeleton");
		void addResources(String resource_path, WIN32_FIND_DATAA find_data,StringVector *ResourceDirectories);
		
		RenderEngineSystem *     mRenderEngineSystem;
	    UndoManager *m_UndoManager;
		///< The Platform Dependent System Pointer
		PROJECTOPTIONS       m_ProjectOptions; ///< Variable holding all project options for current Scene
		 ///< The Current Scene Manager Pointer
		CBaseEditor        *m_SceneManagerEditor; ///< The Current Scene Manager Editor Pointer
		
		CBaseEditor        *m_RootEditor; ///< Ponter to CBaseEditor (Actual Root of All Editors in Scene)
		CBaseEditor        *m_SelectedEditor; ///< Pointer to the Current Selected Object
		
		RegistrationMap m_TypeList; ///< Hash Map of All Registered Editor Types
		StringVector  m_SortedTypeList; ///< Sorted by TypeID StringVector containing Type Names
		NameObjectPairList  m_NameList; ///< Hash Map of All OBjects By Name
		NameObjectPairList  m_NamesByType[LAST_EDITOR]; ///< Type Specific Hash Maps
		NameObjectPairList  m_NamesByTypeID[OGITOR_MAX_OBJECT_TYPE]; ///< Type ID Specific Hash Maps
		NameObjectPairList  m_UpdateList; ///<	Update Queue
		NameObjectPairList  m_RendList; //		RendList;
		ObjectVector        m_PostSceneUpdateList; ///< Update List that is called after each scene load
		SerializerMap       m_SerializerList; ///< Hash Map of All Registered Serializers
		CategoryBarVector   m_CategoryBars; ///< Vector of All Registered Category Bars
		AlignedObjectArray<ApoRootListener*> m_RootListeners; ///< List of objects receiving root notifications
		AlignedObjectArray<DynLib*> m_PluginLibs; ///< Vector List to the loaded Plugins
		StringVector		m_MaterialNames; ///< A List of Material Names in the current user assets directories
		CustomPropertyList  m_CustomProperties; ///< A List containing currently available Custom Property Types
		Vector3				m_LastTranslationDelta;
		unsigned int        m_ObjCounter;
	
		CBaseEditor        *m_TerrainEditorObject;
		bool                m_IsSceneModified;
		bool                m_IsSceneLoaded;
		bool                m_GlobalLightVisiblity; ///< Global variable determining Light Helper Visibility
		bool                m_GlobalCameraVisiblity; ///< Global variable determining Camera Helper Visibility
	
		EditNode    *m_SelectionNode;
		EditNode    *m_WidgetNode; ///< Pointer to Main Widget Node
		EditNode    *m_WidgetX; ///< Pointer to X Axis Widget Node
		EditNode    *m_WidgetY; ///< Pointer to Y Axis Widget Node
		EditNode    *m_WidgetZ; ///< Pointer to Z Axis Widget Node
		int                 m_OldWidgetMode;
		int                 m_OldWidgetAxis;
		AlignedObjectArray<int>    m_ObjectDisplayOrder;
		bool                m_ClearScreenBackground;

		WidgetMap           m_GlobalWidgetsList;

		/// Recursively Fills a Tree View with Object Names andICons
		void RecurseFillTreeView(CBaseEditor *pEditor, void *parent);
		/// Recursively Loads Subproperties of Custom Properties
		void RecurseLoadCustomProperty(TiXmlElement *e,CustomPropertyList& list);
		/// Returns true if an Object Type is in the StringVector
		bool IsCustomTypeRestricted(StringVector &rest,unsigned int type);
		/// Finds and Registers Editor Object Types
		void RegisterAllEditorObjects();

		//Creates the Axis Widgets
		void CreateWidgets();
		//Destroys the Axis Widgets
		void DestroyWidgets();
		//Updates the Widgets' Position
		void UpdateWidgets();
	};

	//extern SocketClientLibExport  ClientRoot ClientRoot::getInstance() ;
}
